Skip to content
This repository has been archived by the owner on Jun 5, 2019. It is now read-only.

Latest commit

 

History

History
343 lines (278 loc) · 14.6 KB

3 - Deployer l'application sur le Cluster.md

File metadata and controls

343 lines (278 loc) · 14.6 KB

Deployer l'application sur le Cluster

Maintenant que l'application et le cluster sont prêts nous allons voir comment héberger les images ainsi que les déployer sur le cluster Kubernetes.

A l'image des fichier docker-compose, les fichiers de configuration pour Kubernetes sont écrient en yaml. Pour chaque étape nous créerons un fichier yaml contenant les configurations de chaque service de l'application. Pour ce Techlab nous avons disposé des fichiers vides dans le répertoire src/kube.

Information 💡

Comme nous voulons que cela soit déployé en même temps, nous mettrons chaque manifeste de chaque service dans le même fichier tout en veillant à bien séparer les manifestes par ---.

Deploiement de lab-survey-redis

Pour qu'une application soit déployée et soit accessible hors du pod sur Kubernetes, il faut déclarer deux ressources : un Deployment et un Service.

Deploiement de la base de donnée

Pour le déployment on donnera comme metadata :

  • un nom lab-survey-redis afin d'identifier la base de donnée.

La partie spec correspond aux configurations de votre pod, par le champ replicat qui permettra de définir le nombre d'instance qu'y devront être déployées par l'orchestrateur et le champs template qui, un peu comme un docker-compose, définit l'application.

Ce template comporte des metadata, permettant de donner un label qui permettra au service de matcher avec le pod, et à nouveau un champs spec où on pourra définir le container. En prenant exemple sur le docker compose, nous le nommerons lab-survey-redis. On prendra l'image redis et on précisera qu'on expose le port de redis (6379) du container grâce à containerPort: 6379.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: lab-survey-redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: lab-survey-redis
  template:
    metadata:
      labels:
        app: lab-survey-redis
    spec:
      containers:
        - name: lab-survey-redis
          image: redis
          ports:
            - containerPort: 6379

Exposer la base de donnée à l'intérieur du cluster

Pour pouvoir exposer cette application de manière publique, ou comme dans notre cas entre deux pods, il faut lui déclarer un service. Pour ce faire, il faut déclarer un kind de type service, puis lui donner un nom lab-survey-redis. Ensuite, nous définirons les spec du service :

  • le port exposé, 6379.
  • Il faut aussi définir quel pod utiliser. Avec Kubernetes la bonne manière est de se baser sur les labels afin de matcher les services à une application. Dans ce cas, il faut utiliser le paramètre selector et nous lui donnerons donc simplement la règle app: lab-survey-redis qui est celle définie dans notre déploiement.

Le service par défaut sur Kubernetes est le ClusterIP, cela permet d'exposer un ou des pods (par répartition de charge) à d'autre à l'intérieur du cluster.

apiVersion: v1
kind: Service
metadata:
  name: lab-survey-redis
spec:
  ports:
    - port: 6379
  selector:
    app: lab-survey-redis

Nous mettrons ces deux manifestes dans un fichier, que nous nommerons lab-survey-redis.yaml et nous créerons les ressources grâce à la commande create en spécifiant le fichier avec le paramètre -f.

$ kubectl create -f lab-survey-redis.yaml
deployment "lab-survey-redis" created
service "lab-survey-redis" created

Deploiement lab-survey-api

Information 💡

Dans l'optique où vous n'auriez pas fait l'étape 1, nous avons déposé des images sur le Docker Hub :

Le déploiement de l'api

Il faut maintenant préparer le manifest du déploiement, nous prendrons donc lab-survey-api comme nom.

En plus du template du pod, nous allons alors spécifier que nous ne voulons qu'une instance de ce pod, replicas: 1, et que la stratégie de mise à jour, en mise à jour part lot (rollingUpdate), sera de mettre à jour avec seulement une seule instance indisponible et en déployant une instance à la fois.

La partie spec de ce template se découpe en deux partie.

La première est l'imagePullSecrets qui permet de définir quel secret prendre pour se connecter à la docker registry, nous lui spécifierons donc azureregistry.

La seconde partie est la définiont du containers que nous configurerons comme suit :

  • Un nom, qui sera donc lab-survey-api.
  • l'image docker que nous utiliserons. Nous prendrons donc, sur notre registry soattechlabregistry.azurecr.io, l'image lab-survey-api et plus précisément la version du tag 1.0.
  • Comme pour le docker-compose.yaml nous donnons deux variables d'environement (env) :
    • REDIS avec comme valeur le nom du service exposant la base de donnée (lab-survey-redis)
    • ASPNETCORE_ENVIRONMENT qui contiendra Production pour que l'application prenne la bonne configuration.
  • Pour les ports, nous exposerons le port 5000, qu'utilise l'application en .Net Core.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: lab-survey-api
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: lab-survey-api
  template:
    metadata:
      labels:
        app: lab-survey-api
    spec:
      imagePullSecrets:
        - name: azureregistry
      containers:
        - name: lab-survey-api
          image: soattechlabregistry.azurecr.io/lab-survey-api:1.0
          env:
            - name: REDIS
              value: 'lab-survey-redis'
            - name: ASPNETCORE_ENVIRONMENT
              value: 'Production'
          ports:
            - containerPort: 5000

Exposition public de l'api

Maintenant que le pod du front est fait, il faut s'occuper du service qui nous permettra d'exposer l'api. Pour cela, on refait un service comme sur le redis et le selector sera app: lab-survey-api, permettant de trouver les pods du front. La partie changeante sera celle sur le port, que nous nommerons http, car nous souhaitons déclarer une redirection du port 80 vers le port 5000 de l'application.

apiVersion: v1
kind: Service
metadata:
  name: lab-survey-api
spec:
  ports:
    - name: http
      port: 80
      targetPort: 5000
  selector:
    app: lab-survey-api

Comme pour la base de donnée, nous réunirons les manifests en un fichier lab-survey-api.yaml que nous passerons à kubectl create grâce au paramètre -f.

$ kubectl create -f lab-survey-api.yaml
deployment "lab-survey-api" created
service "lab-survey-api" created

Deploiement lab-survey-front

Maintenant qu'on a deployé deux instances, je vous laisse imaginer que nous allons déployer le front. En partant sur ce que l'on sait déjà, je vous laisse imaginer le contenue du fichier lab-survey-front.yaml.

Je vous mets la réponse ci dessous au cas où :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: lab-survey-front
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: lab-survey-front
  template:
    metadata:
      labels:
        app: lab-survey-front
    spec:
      imagePullSecrets:
        - name: azureregistry
      containers:
        - name: lab-survey-front
          image: soattechlabregistry.azurecr.io/lab-survey-front:1.0
          ports:
            - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: lab-survey-front
spec:
  ports:
    - name: http
      port: 80
      targetPort: 80
  selector:
    app: lab-survey-front

Test du deploiement

Afin de pouvoir tester l'application, et pouvoir s'en servir, il faut pouvoir y accèder depuis l'extérieur du Cluster. Pour cela, vous avez deux grandes solutions :

  • Configurer le service lab-survey-front en service de type LoadBalancer, mais cela demenderait soit de configurer l'api en public avec un type LoadBalancer aussi, soit coder un reverse proxy pour que le front appel l'api via son Nginx. Dans tous les cas cette solution pose le problème que si pour chacun des services que vous exposez, vous récupérerez une adresse IP, votre provider de cloud va rapidement vous avertir que vous avez des limites, et qu'après cela sera payant (vu la raretée des IPv4)
  • Créer un Ingress devant les services afin de servir justement de reverse proxy et de limiter à une IP pour tous les services que l'ingress reroutera. Cela est plutôt une bonne pratique quand vous n'êtes pas sur un cluster on promise.

Nous allons donc partir sur la création d'un Ingress en se servant de controllers implémentés par nginx-ingress, mais avant cela, nous nous occuperons du manifest de cette ingress. Donc le kind sera Ingress, nous le nomerons lab-survey et nous ajouterons l'annotation nginx.ingress.kubernetes.io/rewrite-target: / afin de faire croire aux targets que nous les appellons directement à partir de leur racine comme ils s'y attendent. Pour la partie rules nous définirons la partie http avec 2 path :

  • / Qui devra servir le service lab-survey-front sur le port 80
  • /api Qui devra servir le service lab-survey-api sur le port 80

Cela nous donnera un fichier, que nous nommerons lab-survey-ingress.yaml, qui devrait ressembler à ceci :

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: lab-survey
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - http:
        paths:
          - path: /
            backend:
              serviceName: lab-survey-front
              servicePort: 80
          - path: /api
            backend:
              serviceName: lab-survey-api
              servicePort: 80

Il nous reste l'ingresse controller et pour cela nous utiliserons helm afin de mettre en place un ingress de type nginx-ingress grâce au package stable/nginx-ingress, la commande helm install et le paramètre name afin de lui donner un nom comme reverse-proxy . Cela donne helm install stable/nginx-ingress --name reverse-proxy --set rbac.create=false.

> helm install stable/nginx-ingress --name reverse-proxy --set rbac.create=false
NAME:   reverse-proxy
LAST DEPLOYED: Tue Jul 31 11:35:13 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                                    DATA  AGE
reverse-proxy-nginx-ingress-controller  1     2s

==> v1/Service
NAME                                         TYPE          CLUSTER-IP    EXTERNAL-IP  PORT(S)                     AGE
reverse-proxy-nginx-ingress-controller       LoadBalancer  10.0.164.182  <pending>    80:30584/TCP,443:31557/TCP  2s
reverse-proxy-nginx-ingress-default-backend  ClusterIP     10.0.63.133   <none>       80/TCP                      1s

==> v1beta1/Deployment
NAME                                         DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
reverse-proxy-nginx-ingress-controller       1        1        1           0          1s
reverse-proxy-nginx-ingress-default-backend  1        1        1           0          1s

==> v1beta1/PodDisruptionBudget
NAME                                         MIN AVAILABLE  MAX UNAVAILABLE  ALLOWED DISRUPTIONS  AGE
reverse-proxy-nginx-ingress-controller       1              N/A              0                    1s
reverse-proxy-nginx-ingress-default-backend  1              N/A              0                    1s

==> v1/Pod(related)
NAME                                                         READY  STATUS             RESTARTS  AGE
reverse-proxy-nginx-ingress-controller-6f97d7bfff-qq9xj      0/1    ContainerCreating  0         1s
reverse-proxy-nginx-ingress-default-backend-b48c99776-27wx7  0/1    ContainerCreating  0         1s


NOTES:
The nginx-ingress controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace default get services -o wide -w reverse-proxy-nginx-ingress-controller'

An example Ingress that makes use of the controller:

  apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      kubernetes.io/ingress.class: nginx
    name: example
    namespace: foo
  spec:
    rules:
      - host: www.example.com
        http:
          paths:
            - backend:
                serviceName: exampleService
                servicePort: 80
              path: /
    # This section is only required if TLS is to be enabled for the Ingress
    tls:
        - hosts:
            - www.example.com
          secretName: example-tls

If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:

  apiVersion: v1
  kind: Secret
  metadata:
    name: example-tls
    namespace: foo
  data:
    tls.crt: <base64 encoded cert>
    tls.key: <base64 encoded key>
  type: kubernetes.io/tls

Avant de pouvoir tester, il va falloir récupérer l'ip public, le tempalte helm nous communique le moyen le plus simple de le faire donc nous ferons kubectl --namespace default get services -o wide -w reverse-proxy-nginx-ingress-controller

> kubectl --namespace default get services -o wide -w reverse-proxy-nginx-ingress-controller
NAME                                     TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE       SELECTOR
reverse-proxy-nginx-ingress-controller   LoadBalancer   10.0.164.182   13.80.0.86    80:30584/TCP,443:31557/TCP   4h        app=nginx-ingress,component=controller,release=reverse-proxy

Donc en allant sur l'EXTERNAL-IP, 13.80.0.86 dans mon cas, nous devrions tomber sur l'application et elle doit être totalement fonctionnelle. preview de l'application

Félicitation, vous avez déployé votre premiere application avec un cluster Kubernetes sur azure. 🎊🏆🎉

Si vous êtes là, normalement, vous avez déployés votre première application dans un cluster Kubernetes sur azure tout en permettant de découpler les ressources de l'application, un serveur redis et votre code.

Bonus : Economisez de l'argent

Lors de ce Techlab nous avons crée des ressources, quand nous aurons finis de les utiliser, il serait bien de les supprimer afin d'arrêter leur facturation. C'est une des raisons expliquant que nous avons crée les ressources dans un ressource groupe dédié. Pour cela, nous utiliserons la sous commande delete de la commande az group ce qui donnera az group delete --name soat-techlab.

> az group delete --name soat-techlab
Are you sure you want to perform this operation? (y/n): Y